package com.fxcalibre.hibernate;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.type.Type;

import com.fxcalibre.db.beans.HibernateBean;

@SuppressWarnings("deprecation")
public class HibernateUtils
{

	public static int OK = 0;
	public static int N_OK = 1;
	private static final SessionFactory sessionFactory;

	public static SessionFactory getSessionFactory()
	{
		return sessionFactory;
	}

	public static int grabar(Object bean)
	{
		int resultado = N_OK;
		Session session = null;
		try
		{
			session = getSessionFactory().getCurrentSession();
			session.beginTransaction();

			session.saveOrUpdate(bean);
			session.getTransaction().commit();
			resultado = OK;
		} catch (HibernateException he)
		{
			he.printStackTrace();
			// logger.info("error " + he, he);

			// logger.info("Intentando cerrar la conexion a la base de datos...");
			Connection conn = session.close();
			try
			{
				if (conn == null)
				{
					// logger.info("Cerrada la conexion a la base de datos tras la excepcion");
				} else
				{
					conn.close();
					// logger.info("Cerrada la conexion a la base de datos tras la excepcion");
				}

			} catch (SQLException ex)
			{
				// logger.i//loggerrror al intentar cerra la conexion a la base
				// de datos tras la excepcion");
			}

			// logger.info("Se ha intentado cerrar la conexion de base de datos.");
		}

		return resultado;
	}

	public static boolean borrar(Object bean)
	{
		boolean resultado = false;
		try
		{
			Session session = getSessionFactory().getCurrentSession();
			session.beginTransaction();
			session.delete(bean);
			session.getTransaction().commit();
			resultado = true;
		} catch (HibernateException he)
		{
			// logger.error("Error al borrar el objeto.", he);
		}
		return resultado;
	}

	public static int delete(String query)
	{
		int resultado = N_OK;
		try
		{
			Session session = getSessionFactory().getCurrentSession();
			session.beginTransaction();
			Query delQry = session.createSQLQuery(query);
			delQry.executeUpdate();
			session.getTransaction().commit();
			resultado = OK;
		} catch (Exception he)
		{
			// logger.error("Error al borrar el objeto.", he);
		}
		return resultado;
	}

	public static Object buscarPorId(String entidad, int beanId)
	{
		Object object = null;
		try
		{
			Session session = getSessionFactory().getCurrentSession();
			session.beginTransaction();
			object = session.get(entidad, new Integer(beanId));
			session.getTransaction().commit();
		} catch (HibernateException he)
		{
			// logger.error("Error al buscar el objeto " + entidad + " : " +
			// beanId, he);
		}
		return object;
	}

	public static Object buscarPorId(Class<?> c, Serializable beanId)
	{
		return buscarPorId(c, beanId, true);
	}

	public static Object buscarPorId(Class<?> c, Serializable beanId, boolean lazyLoad)
	{
		Object object = null;
		try
		{
			Session session = getSessionFactory().getCurrentSession();
			session.beginTransaction();
			object = session.get(c.getName(), beanId);
			if (!lazyLoad && object instanceof HibernateBean)
			{
				((HibernateBean) object).initialize();
			}

			session.getTransaction().commit();
		} catch (Exception he)
		{
			he.printStackTrace();
			// logger.debug("Error al buscar el objeto " + c.getName() + " : " +
			// beanId);
		}
		return object;
	}

	public static Object buscarPorId(String entidad, Serializable beanId)
	{
		Object object = null;
		try
		{
			Session session = getSessionFactory().getCurrentSession();
			session.beginTransaction();
			object = session.get(entidad, beanId);
			session.getTransaction().commit();
		} catch (Exception he)
		{
			// logger.debug("Error al buscar el objeto " + entidad + " : " +
			// beanId);
		}
		return object;
	}

	public static <K> List<?> buscar(GenericCriteria gCriteria)
	{
		List<?> result = null;
		try
		{
			Session session = getSessionFactory().getCurrentSession();
			session.beginTransaction();
			Criteria criteria = session.createCriteria(gCriteria.getEntity());
			List<Criterion> where = gCriteria.getWhere();
			for (int i = 0; i < where.size(); i++)
			{
				criteria.add((Criterion) where.get(i));
			}
			List<Order> order = gCriteria.getOrder();
			for (int i = 0; i < order.size(); i++)
			{
				criteria.addOrder((Order) order.get(i));
			}

			Map<String, Criterion> subcriterias = gCriteria.getSubcriterias();
			Iterator<String> i = subcriterias.keySet().iterator();
			while (i.hasNext())
			{
				String relationShip = i.next();
				Criteria subCrit = criteria.createCriteria(relationShip);
				subCrit.add(subcriterias.get(relationShip));
			}

			result = criteria.list();
			session.getTransaction().commit();
		} catch (HibernateException he)
		{
			// logger.error("Error al buscar el objeto.", he);
			he.printStackTrace();
		}
		return result;
	}

	public static List<?> buscar(GenericCriteria criterio, int maxRows)
	{
		return buscar(criterio, maxRows, 0);
	}

	public static List<?> buscar(GenericCriteria criterio, int maxRows, int startIndex)
	{
		List<?> result = null;
		try
		{
			Session session = getSessionFactory().getCurrentSession();
			session.beginTransaction();
			Criteria criteria = session.createCriteria(criterio.getEntity());
			List<Criterion> where = criterio.getWhere();
			for (int i = 0; i < where.size(); i++)
			{
				criteria.add((Criterion) where.get(i));
			}
			List<Order> order = criterio.getOrder();
			for (int i = 0; i < order.size(); i++)
			{
				criteria.addOrder((Order) order.get(i));
			}

			criteria.setMaxResults(maxRows);
			criteria.setFirstResult(startIndex);
			result = criteria.list();
			session.getTransaction().commit();
		} catch (Exception he)
		{
			// logger.error("Error al buscar el objeto.", he);
		}
		return result;
	}

	public static List<?> executeQuery(String query)
	{
		List<?> result = null;
		try
		{
			Session session = getSessionFactory().getCurrentSession();
			session.beginTransaction();
			Query q = session.createQuery(query);
			result = q.list();
			session.getTransaction().commit();
		} catch (Exception he)
		{
			he.printStackTrace();
			// logger.error("Error al ejecutar query: " + query, he);
		}
		return result;
	}

	public static List<?> executeQuery(String query, Type[] types, Object[] values)
	{
		List<?> result = null;
		try
		{
			Session session = getSessionFactory().getCurrentSession();
			session.beginTransaction();
			Query q = session.createQuery(query);
			q.setParameters(values, types);
			result = q.list();
			session.getTransaction().commit();
		} catch (Exception he)
		{
			// logger.error("Error al ejecutar query: " + query, he);
		}
		return result;
	}

	static
	{
		try
		{
			sessionFactory = new Configuration().configure().buildSessionFactory();
		} catch (Throwable ex)
		{
			// logger.error("Initial SessionFactory creation failed." + ex, ex);
			throw new ExceptionInInitializerError(ex);
		}
	}
}